package rad.framework.uml2.presentation;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.StringTokenizer;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.dialogs.WizardNewFileCreationPage;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Profile;
import org.eclipse.uml2.uml.UMLFactory;
import org.eclipse.uml2.uml.UMLPackage;

import rad.framework.uml2.uml.edit.UMLEditPlugin;


/**
 * un simple assistant pour creer un nouveau fichier model
 * 
 * @author boudyacho
 */
public class UML2ModelWizard extends Wizard implements INewWizard {

	public static final String copyright = "";

	protected UMLPackage uml2Package = UMLPackage.eINSTANCE;

	protected UMLFactory uml2Factory = uml2Package.getUMLFactory();

	protected UML2ModelWizardNewFileCreationPage newFileCreationPage;

	protected UML2ModelWizardInitialObjectCreationPage initialObjectCreationPage;

	protected IStructuredSelection selection;

	protected IWorkbench workbench;

	protected List initialObjectNames;

	public void init(IWorkbench workbench, IStructuredSelection selection) {
		this.workbench = workbench;
		this.selection = selection;
		setWindowTitle(UML2EditorPlugin.INSTANCE.getString("_UI_Wizard_label"));
		setDefaultPageImageDescriptor(ExtendedImageRegistry.INSTANCE.getImageDescriptor(UML2EditorPlugin.INSTANCE.getImage("full/wizban/NewUML2")));
	}

	protected Collection getInitialObjectNames() {
		if (initialObjectNames == null) {
			initialObjectNames = new ArrayList();
			initialObjectNames.add("Model");

		}
		return initialObjectNames;
	}

	protected EObject createInitialModel() {
		final EClass eClass = (EClass) uml2Package.getEClassifier(initialObjectCreationPage.getInitialObjectName());
		final EObject rootObject = uml2Factory.create(eClass);
		final List<String> profiles = getProfiles();
		for (final String string : profiles) {
			try {
				importProfile((Package) rootObject, string);
			} catch (final Exception e) {
				throw new RuntimeException("Loading Profile: " + string, e);
			}
		}
		return rootObject;
	}

	protected List<String> getProfiles() {
		final List<String> profiles = new ArrayList<String>();
		final IExtensionRegistry registry = Platform.getExtensionRegistry();
		final IExtensionPoint point = registry.getExtensionPoint("rad.framework.mda.profiles.profiles");
		if (point == null) {
			throw new RuntimeException("No profiles defined");
		}
		final IExtension[] extensions = point.getExtensions();
		for (final IExtension extension : extensions) {
			final IConfigurationElement[] ce = extension.getConfigurationElements();
			for (final IConfigurationElement element : ce) {
				profiles.add(element.getAttribute("id"));
			}
		}
		return profiles;
	}

	protected void importProfile(Package package_, String path) {
		final Profile profile = (Profile) load(URI.createURI(path));
		package_.applyProfile(profile);
	}

	protected Package load(URI uri) {
		final ResourceSet resourceSet = new ResourceSetImpl();
		Package package_ = null;
		try {
			final Resource resource = resourceSet.getResource(uri, true);

			package_ = (Package) EcoreUtil.getObjectByType(resource.getContents(), UMLPackage.eINSTANCE.getPackage());
		} catch (final WrappedException we) {
			throw new RuntimeException(we);
		}
		return package_;
	}

	@Override
	public boolean performFinish() {
		try {

			final IFile modelFile = getModelFile();

			final WorkspaceModifyOperation operation = new WorkspaceModifyOperation() {
				@Override
				protected void execute(IProgressMonitor progressMonitor) {
					try {

						final ResourceSet resourceSet = new ResourceSetImpl();

						final URI fileURI = URI.createPlatformResourceURI(modelFile.getFullPath().toString());

						final Resource resource = resourceSet.createResource(fileURI);

						final EObject rootObject = createInitialModel();
						if (rootObject != null) {
							resource.getContents().add(rootObject);
						}

						final Map options = new HashMap();
						options.put(XMLResource.OPTION_ENCODING, initialObjectCreationPage.getEncoding());
						resource.save(options);
					} catch (final Exception exception) {
						UML2EditorPlugin.INSTANCE.log(exception);
					} finally {
						progressMonitor.done();
					}
				}
			};

			getContainer().run(false, false, operation);

			return true;
		} catch (final Exception exception) {
			UML2EditorPlugin.INSTANCE.log(exception);
			return false;
		}
	}

	public class UML2ModelWizardNewFileCreationPage extends WizardNewFileCreationPage {

		public UML2ModelWizardNewFileCreationPage(String pageId, IStructuredSelection selection) {
			super(pageId, selection);
		}

		@Override
		protected boolean validatePage() {
			if (super.validatePage()) {

				final String requiredExt = UML2EditorPlugin.INSTANCE.getString("_UI_UML2EditorFilenameExtension");
				final String enteredExt = new Path(getFileName()).getFileExtension();
				if (enteredExt == null || !enteredExt.equals(requiredExt)) {
					setErrorMessage(UML2EditorPlugin.INSTANCE.getString("_WARN_FilenameExtension", new Object[] {
						requiredExt
					}));
					return false;
				} else {
					return true;
				}
			} else {
				return false;
			}
		}

		public IFile getModelFile() {
			return ResourcesPlugin.getWorkspace().getRoot().getFile(getContainerFullPath().append(getFileName()));
		}
	}

	public class UML2ModelWizardInitialObjectCreationPage extends WizardPage {

		protected Combo initialObjectField;

		protected List encodings;

		protected Combo encodingField;

		public UML2ModelWizardInitialObjectCreationPage(String pageId) {
			super(pageId);
		}

		public void createControl(Composite parent) {
			final Composite composite = new Composite(parent, SWT.NONE);
			{
				final GridLayout layout = new GridLayout();
				layout.numColumns = 1;
				layout.verticalSpacing = 12;
				composite.setLayout(layout);

				final GridData data = new GridData();
				data.verticalAlignment = GridData.FILL;
				data.grabExcessVerticalSpace = true;
				data.horizontalAlignment = GridData.FILL;
				composite.setLayoutData(data);
			}

			final Label containerLabel = new Label(composite, SWT.LEFT);
			{
				containerLabel.setText(UML2EditorPlugin.INSTANCE.getString("_UI_ModelObject"));

				final GridData data = new GridData();
				data.horizontalAlignment = GridData.FILL;
				containerLabel.setLayoutData(data);
			}

			initialObjectField = new Combo(composite, SWT.BORDER);
			{
				final GridData data = new GridData();
				data.horizontalAlignment = GridData.FILL;
				data.grabExcessHorizontalSpace = true;
				initialObjectField.setLayoutData(data);
			}

			for (final Iterator i = getInitialObjectNames().iterator(); i.hasNext();) {
				initialObjectField.add(getLabel((String) i.next()));
			}

			if (initialObjectField.getItemCount() == 1) {
				initialObjectField.select(0);
			}
			initialObjectField.addModifyListener(validator);

			final Label encodingLabel = new Label(composite, SWT.LEFT);
			{
				encodingLabel.setText(UML2EditorPlugin.INSTANCE.getString("_UI_XMLEncoding"));

				final GridData data = new GridData();
				data.horizontalAlignment = GridData.FILL;
				encodingLabel.setLayoutData(data);
			}
			encodingField = new Combo(composite, SWT.BORDER);
			{
				final GridData data = new GridData();
				data.horizontalAlignment = GridData.FILL;
				data.grabExcessHorizontalSpace = true;
				encodingField.setLayoutData(data);
			}

			for (final Iterator i = getEncodings().iterator(); i.hasNext();) {
				encodingField.add((String) i.next());
			}

			encodingField.select(0);
			encodingField.addModifyListener(validator);

			setPageComplete(validatePage());
			setControl(composite);
		}

		protected ModifyListener validator = new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				setPageComplete(validatePage());
			}
		};

		protected boolean validatePage() {
			return getInitialObjectName() != null && getEncodings().contains(encodingField.getText());
		}

		@Override
		public void setVisible(boolean visible) {
			super.setVisible(visible);
			if (visible) {
				if (initialObjectField.getItemCount() == 1) {
					initialObjectField.clearSelection();
					encodingField.setFocus();
				} else {
					encodingField.clearSelection();
					initialObjectField.setFocus();
				}
			}
		}

		public String getInitialObjectName() {
			final String label = initialObjectField.getText();

			for (final Iterator i = getInitialObjectNames().iterator(); i.hasNext();) {
				final String name = (String) i.next();
				if (getLabel(name).equals(label)) {
					return name;
				}
			}
			return null;
		}

		public String getEncoding() {
			return encodingField.getText();
		}

		protected String getLabel(String typeName) {
			try {
				return UMLEditPlugin.INSTANCE.getString("_UI_" + typeName + "_type");
			} catch (final MissingResourceException mre) {
				UML2EditorPlugin.INSTANCE.log(mre);
			}
			return typeName;
		}

		protected Collection getEncodings() {
			if (encodings == null) {
				encodings = new ArrayList();
				for (final StringTokenizer stringTokenizer = new StringTokenizer(UML2EditorPlugin.INSTANCE.getString("_UI_XMLEncodingChoices")); stringTokenizer.hasMoreTokens();) {
					encodings.add(stringTokenizer.nextToken());
				}
			}
			return encodings;
		}
	}

	@Override
	public void addPages() {

		newFileCreationPage = new UML2ModelWizardNewFileCreationPage("Whatever", selection);
		newFileCreationPage.setTitle(UML2EditorPlugin.INSTANCE.getString("_UI_UML2ModelWizard_label"));
		newFileCreationPage.setDescription(UML2EditorPlugin.INSTANCE.getString("_UI_UML2ModelWizard_description"));
		newFileCreationPage.setFileName(UML2EditorPlugin.INSTANCE.getString("_UI_UML2EditorFilenameDefaultBase") + "." + UML2EditorPlugin.INSTANCE.getString("_UI_UML2EditorFilenameExtension"));
		addPage(newFileCreationPage);

		if (selection != null && !selection.isEmpty()) {

			final Object selectedElement = selection.iterator().next();
			if (selectedElement instanceof IResource) {

				IResource selectedResource = (IResource) selectedElement;
				if (selectedResource.getType() == IResource.FILE) {
					selectedResource = selectedResource.getParent();
				}

				if (selectedResource instanceof IFolder || selectedResource instanceof IProject) {

					newFileCreationPage.setContainerFullPath(selectedResource.getFullPath());

					final String defaultModelBaseFilename = UML2EditorPlugin.INSTANCE.getString("_UI_UML2EditorFilenameDefaultBase");
					final String defaultModelFilenameExtension = UML2EditorPlugin.INSTANCE.getString("_UI_UML2EditorFilenameExtension");
					String modelFilename = defaultModelBaseFilename + "." + defaultModelFilenameExtension;
					for (int i = 1; ((IContainer) selectedResource).findMember(modelFilename) != null; ++i) {
						modelFilename = defaultModelBaseFilename + i + "." + defaultModelFilenameExtension;
					}
					newFileCreationPage.setFileName(modelFilename);
				}
			}
		}
		initialObjectCreationPage = new UML2ModelWizardInitialObjectCreationPage("Whatever2");
		initialObjectCreationPage.setTitle(UML2EditorPlugin.INSTANCE.getString("_UI_UML2ModelWizard_label"));
		initialObjectCreationPage.setDescription(UML2EditorPlugin.INSTANCE.getString("_UI_Wizard_initial_object_description"));
		addPage(initialObjectCreationPage);
	}

	public IFile getModelFile() {
		return newFileCreationPage.getModelFile();
	}

}
